library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.processor_types.all;

architecture structure2 of processor is
    component alu is
	port (
		clock: in std_ulogic;
        reset : in std_ulogic;
        alu_control: in alu_bus;
        in1 : in bit32;
        in2 : in bit32;
		result : out bit32
	);
    end component;
    
    component ir is
	port (
		instruction: in bit32;
		clock: in std_ulogic;
        reset : in std_ulogic;
        instr_sel : in std_ulogic;
		opcode: out bit6;
        reg_s : out bit5;
        reg_t : out bit5;
        reg_d : out bit5;
        reg_h : out bit5;
        func_alu : out bit6;
        jmp_addr : out bit26;
        immed     : out bit16
	);
    end component;
    
    component program_counter is
	port (
		clock: in std_ulogic;
        reset: in std_ulogic;
		jump_select: in std_ulogic;
        branch_select : in std_ulogic;
		jump_value: in bit32;
		null_flag: in std_ulogic;
        incr_pc : in std_ulogic;
		pc_value: out bit32
	);
    end component;

    component registers is
	port (
		clock : in std_ulogic;
        reset : in std_ulogic;
        rw_sel : in std_ulogic;
        reg_select_1 : in bit5;
        reg_select_2 : in bit5;
        reg_write    : in bit5;
		in_value : in bit32;
        out_value_1 : out bit32;
        out_value_2 : out bit32
	);
    end component;
    
    component control is
	port (
		clock: in std_ulogic;
        reset: in std_ulogic;
		opcode: in bit6;
        func: in bit6;
		reg_s : in bit32;
		alu_control: out alu_bus;
		mux_control: out std_ulogic;
        reg_rw_sel : out std_ulogic;
        pc_jump_sel : out std_ulogic;
        pc_branch_sel : out std_ulogic;
        incr_pc : out std_ulogic;
        ir_sel : out std_ulogic;
        alu_in_sel : out alu_input_select;
        reg_write_source : out std_ulogic;
        write : out std_ulogic;
        read : out std_ulogic;
        ready : in std_ulogic;
		done : out std_ulogic
	);
    end component;
    
    signal alu_control : alu_bus;
    signal alu_in1, alu_in2, alu_result : bit32;
    signal ir_sel : std_ulogic;
    signal ir_opcode, ir_func_alu: bit6;
    signal reg_s, reg_t, reg_d, reg_h, reg_write : bit5;
    signal ir_jmp_addr : bit26;
    signal ir_immed    : bit16;
    signal pc_jump_sel, pc_branch_sel, pc_null_flag, incr_pc : std_ulogic;
    signal pc_value : bit32;
    signal reg_rw_sel, reg_write_source : std_ulogic;
    signal reg_out1, reg_out2, reg_in : bit32;
    signal mux_select : std_ulogic;
    signal alu_in_select : alu_input_select;
	
begin
    ctrl: control
		port map (clock, reset, ir_opcode, ir_func_alu, reg_out1, alu_control, mux_select, reg_rw_sel, pc_jump_sel, pc_branch_sel, incr_pc, ir_sel, alu_in_select, reg_write_source, write, read, ready, done);
	rgs : registers
        port map (clock, reset, reg_rw_sel, reg_s, reg_t, reg_write, reg_in, reg_out1, reg_out2);
    pc : program_counter
        port map (clock, reset, pc_jump_sel, pc_branch_sel, alu_result, pc_null_flag, incr_pc, pc_value);
    ir2 : ir
        port map (d_busin, clock, reset, ir_sel, ir_opcode, reg_s, reg_t, reg_d, reg_h, ir_func_alu, ir_jmp_addr, ir_immed);
    al : alu
        port map (clock, reset, alu_control, alu_in1, alu_in2, alu_result);
    
	--(rs_rt, pc_imm, pc_address, rt_rh, rs_imm, res_rt);
    alu_in1 <=  reg_out1 when alu_in_select=rs_rt or alu_in_select=rs_imm else
                reg_out2 when alu_in_select=rt_rh else
                pc_value and X"f0000000" when alu_in_select=pc_address else
                pc_value;
                
    alu_in2 <= reg_out2 when alu_in_select=rs_rt or alu_in_select=res_rt else
                (std_logic_vector(resize(signed(ir_immed), 30)) & "00") when alu_in_select=pc_imm else
                std_logic_vector(resize(signed(ir_immed), 32)) when alu_in_select=rs_imm else
                (std_logic_vector(resize(unsigned(ir_jmp_addr), 30)) & "00") when alu_in_select=pc_address else
				(others=>'0') when alu_in_select=res_null else
                std_logic_vector(resize(unsigned(reg_h), 32));
    reg_in <=   alu_result when reg_write_source='1' else
                d_busin;
    reg_write <=    reg_d when reg_write_source='1' else
                    reg_t;
    d_busout <= reg_out2;
    pc_null_flag <= '1' when (signed(reg_out1) <= 0) else '0';
    
	a_bus <= pc_value when mux_select='1' else
             alu_result;
			  
    res <=  pc_value when ir_opcode=j or ir_opcode=blez else
            d_busin when ir_opcode=lw else
            reg_out2 when ir_opcode=sw else
			dontcare when ir_opcode=rtype and ir_func_alu=mult else
            alu_result;
    
        -- clock : in std_ulogic;
        -- reset : in std_ulogic;
        -- d_busout : out std_logic_vector(31 downto 0);
        -- d_busin : in std_logic_vector(31 downto 0);
        -- a_bus : out std_logic_vector(31 downto 0);
        -- write : out std_ulogic;
        -- read : out std_ulogic;
        -- ready : in std_ulogic;
		-- done : out std_ulogic;
		-- res : out std_logic_vector(31 downto 0)
end structure2;
